import random
import map_game
import copy
import math

class AIMap:
    def __init__(self,boardMap: list = None):
        self.map = [[0 for i in range(4)] for i in range(4)] #初始化 全部清零
        self.map = [[boardMap[i][j]for i in range(4)] for j in range(4)] #复制

    #AI:向左转！
    def ai_go_left(self):
        isAdd = 0 # 表示是否成功移动
        for row in range(0,4):
            index = 0
            for col in range(1,4):
                if self.map[row][col] > 0:
                    if self.map[row][col] == self.map[row][index]:
                        self.map[row][index] = self.map[row][col] + self.map[row][index]
                        self.map[row][col] = 0
                        index += 1
                        isAdd = 1
                    elif self.map[row][index] == 0:
                        self.map[row][index] = self.map[row][col]
                        self.map[row][col] = 0
                        isAdd = 1
                    else:
                        index += 1

                    if self.map[row][index] == 0:
                        self.map[row][index] = self.map[row][col]
                        self.map[row][col] = 0
                        isAdd = 1
        return isAdd

    #AI:向右转！
    def ai_go_right(self):
        isAdd = 0 # 表示是否成功移动
        for row in range(0,4):
            index = 3
            for col in range(2,-1,-1):
                if self.map[row][col] > 0:
                    if self.map[row][col] == self.map[row][index]:
                        self.map[row][index] = self.map[row][col] + self.map[row][index]
                        self.map[row][col] = 0
                        index -= 1
                        isAdd = 1
                    elif self.map[row][index] == 0:
                        self.map[row][index] = self.map[row][col]
                        self.map[row][col] = 0
                        isAdd = 1
                    else:
                        index -= 1

                    if self.map[row][index] == 0:
                        self.map[row][index] = self.map[row][col]
                        self.map[row][col] = 0
                        isAdd = 1
        return isAdd

    #AI:向前进
    def ai_go_up(self):
        isAdd = 0 # 表示是否成功移动
        for col in range(0,4):
            index = 0
            for row in range(1,4):
                if self.map[row][col] > 0:
                    if self.map[row][col] == self.map[index][col]:
                        self.map[index][col] = self.map[row][col] + self.map[index][col]
                        self.map[row][col] = 0
                        index += 1
                        isAdd = 1
                    elif self.map[index][col] == 0:
                        self.map[index][col] = self.map[row][col]
                        self.map[row][col] = 0
                        isAdd = 1
                    else:
                        index += 1

                    if self.map[index][col] == 0:
                        self.map[index][col] = self.map[row][col]
                        self.map[row][col] = 0
                        isAdd = 1
        return isAdd

    #AI:向后退
    def ai_go_down(self):
        isAdd = 0 # 表示是否成功移动
        for col in range(0,4):
            index = 3
            for row in range(2,-1,-1):
                if self.map[row][col] > 0:
                    if self.map[row][col] == self.map[index][col]:
                        self.map[index][col] = self.map[row][col] + self.map[index][col]
                        self.map[row][col] = 0
                        index -= 1
                        isAdd = 1
                    elif self.map[index][col] == 0:
                        self.map[index][col] = self.map[row][col]
                        self.map[row][col] = 0
                        isAdd = 1
                    else:
                        index -= 1

                    if self.map[index][col] == 0:
                        self.map[index][col] = self.map[row][col]
                        self.map[row][col] = 0
                        isAdd = 1
        return isAdd

    #控制AI走不同的方向 走成功为True 走失败为False
    def ai_go(self,dir):#0左 1右 2上 3下
        if dir == 0:#左
            if self.ai_go_left() == 1:
                return True
            else:
                return False
        elif dir == 1:#右
            if self.ai_go_right() == 1:
                return True
            else:
                return False
        elif dir == 2:#上
            if self.ai_go_up() == 1:
                return True
            else:
                return False
        elif dir == 3:#下
            if self.ai_go_down() == 1:
                return True
            else:
                return False
#数值分析
#格局评价
#作为算法的核心，如何评价当前格局的价值是重中之重。
#在2048中，除了终局外，中间格局并无非常明显的价值评价指标，因此需要用一些启发式的指标来评价格局。
#那些分数高的好格局是容易引向胜利的格局，而分低的坏格局是容易引向失败的格局。
    def ai_evaluation(self):
        #参数需要进行调试
        #否则会变成人工智障
        #smoothWeight = 0.5 
        #monoWeight = 0.03  
        #emptyWeight = 2.7  
        #maxWeight = 4
        #disWeight = 10 

        #人工智障2.0参数
        smoothWeight = 0.5
        monoWeight = 0.03
        emptyWeight = 2.7  
        maxWeight = 4
        disWeight = 10 

        result = [disWeight*math.log2(self.dis_weight()), smoothWeight * self.smothness(), monoWeight * self.monotonicity(), 
                  emptyWeight*math.log2(self.empty_num() + 1), maxWeight*self.max_and_submax_num()]
        
        #人工智障3.0参数
        #smoothWeight = 0.1  # 0.5
        #monoWeight = 1.0  # 0.03
        #emptyWeight = 2.7  # 2.7
        #maxWeight = 1  # 0.01
        #disWeight = 0

        #smoothWeight = 0.5
        #monoWeight = 0.03
        #emptyWeight = 2.7  
        #maxWeight = 4
        #disWeight = 10 

        #result = [disWeight*self.dis_weight(), smoothWeight * self.smothness(), monoWeight *
        #          self.monotonicity(), emptyWeight*math.log(self.empty_num()), maxWeight*self.max_num()]
   
        return result
    #单调性
    #单调性指方块从左到右、从上到下均遵从递增或递减。
    ##一般来说，越单调的格局越好。
    #下面是一个具有良好单调格局的例子
    #  8    32    64    512
    #  4     8    16    256
    #  2     4     8     32
    #  0     0     4      8
    def monotonicity(self):
        totals = [0,0,0,0]  # 四个方向的单调性评估  左 右 上 下（单调递增）
        #1.横着
        for i in range(4):
            current = 0
            next = current+1
            while next < 4:
                while next < 4 and self.map[i][next] == 0:
                    next += 1
                if next >= 4:
                    next -= 1

                if self.map[i][current] != 0: 
                    currentValue = math.log2(self.map[i][current])
                else:
                    currentValue = 0

                if self.map[i][next] != 0: 
                    nextValue = math.log2(self.map[i][next])
                else:
                    nextValue = 0

                if currentValue > nextValue:
                    totals[0] += nextValue-currentValue
                else:
                    totals[1] += currentValue-nextValue
                current = next
                next += 1
        #2.竖着
        for i in range(4):
            current = 0
            next = current+1
            while next < 4:
                while next < 4 and self.map[next][i] == 0:
                    next += 1
                if next >= 4:
                    next -= 1

                if self.map[current][i] != 0:
                    currentValue = math.log2(self.map[current][i])
                else:
                    currentValue = 0

                if self.map[next][i] != 0:
                    nextValue = math.log2(self.map[next][i])
                else:
                    nextValue = 0

                if currentValue > nextValue:
                    totals[2] += nextValue-currentValue
                else:
                    totals[3] += currentValue-nextValue
                current = next
                next += 1
        return max(totals[:2])+max(totals[2:])

    #平滑度
    #平滑性是指每个方块与其直接相邻方块数值的差，其中差越小越平滑。
    #例如2旁边是4就比2旁边是128平滑。
    #一般认为越平滑的格局越好。
    #下面是一个具有极端平滑性的例子
    #  1024    1024    1024
    #  1024    1024    1024    1024
    #  1024    1024    1024    1024
    #  1024    1024    1024    1024
    def smothness(self):
        lubricity = 0
        for i in range(4):
            for j in range(4):
                if self.map[i][j] != 0:
                    if i >= 1:
                        # 左边减去该值
                        lubricity -= abs(math.log2(self.map[i-1][j]+1) - math.log2(self.map[i][j]+1))
                    if i < 3:
                        # 右边减去该值
                        lubricity -= abs(math.log2(self.map[i+1][j]+1) - math.log2(self.map[i][j]+1))
                    if j > 0:
                        # 上面减去该值
                        lubricity -= abs(math.log2(self.map[i][j-1]+1) - math.log2(self.map[i][j]+1))
                    if j < 3:
                        # 下面减去该值
                        lubricity -= abs(math.log2(self.map[i][j+1]+1) - math.log2(self.map[i][j]+1))
        return lubricity

    #空格数
    #因为一般来说，空格子越少对玩家越不利。
    #空格越多的格局越好。
    def empty_num(self):
        empty_num = 0
        for i in range(4):
            for j in range(4):
                if self.map[i][j] == 0:
                    empty_num += 1
        return empty_num

    #单个最大的值
    def max_num(self):
        max_num = 0
        for i in range(4):
            for j in range(4):
                if max_num < self.map[i][j]:
                    max_num = self.map[i][j]
        return max_num

    #这个指标评价棋盘的单个数的最大值和总体和
    #值越大格局越好
    def max_and_submax_num(self):
        max_num = 0
        subMaxNum = 0
        for row in range(4):
            for col in range(4):
                if max_num < self.map[row][col]:
                    subMaxNum = max_num + subMaxNum;
                    max_num = self.map[row][col]

        return math.log2(subMaxNum/3+max_num*2/3)  #2.0
        #return subMaxNum/3+max_num*2/3  #3.0

    #分布位置权重
    #整体分布越往下，越往右格局越好
    def dis_weight(self):
        #wei = [[12, 13, 25, 50],
        #       [11, 10, 9, 8],
        #       [4, 5, 6, 7],
        #       [3, 2, 1, 0]]
        wei = [[3, 2, 1, 0],
               [4, 5, 6, 7],
               [16, 10, 9, 8],
               [32,64,128,256]]
        dis_sum = 0
        for j in range(4):
            for i in range(4):
                if self.map[i][j] == 0:  #对数取值不能为0 否则会计算错误
                    continue
                dis_sum += math.log2(self.map[i][j])*wei[i][j]  #对数形式
        return dis_sum

    # 计算分散度，越分散得分越高
    def islands(self):  
        islandsMark = 0
        self.marked = [[True]*4]*4
        for i in range(4):
            for j in range(4):
                if self.map[i][j] != 0:
                    self.marked[i][j] = False
        for i in range(4):
            for j in range(4):
                if self.map[i][j] != 0 and not self.marked[i][j]:
                    islandsMark += 1
                    self.mark(i, j, self.map[i][j])
        return islandsMark

    def mark(self, x, y, value):
        # 四个方向向量，方便遍历时使用
        vectors = [[0, 1], [1, 0], [-1, 0], [0, -1]]
        if x >= 0 and x <= 3 and y >= 0 and y <= 3 and self.map[x][y] != 0 and self.map[x][y] == value and not self.marked[x][y]:
            self.marked[x][y] = True
            for direction in range(4):
                vector = vectors[direction]
                self.mark(x+vector[0], y+vector[1], value)




